﻿using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace Hsenl {
    [FrameworkMember]
    public class Combiner {
        #region Reigster Public Events

        private static readonly Dictionary<int, Combiner> _combiners = new();
        private static bool _disabled; // 禁用
        private static bool _disabledCompositeCombine;
        private static ComponentTypeCacher _enableComponentCompositeTypeCacher;

        public static LogStopwatch Stopwatch = new("Stopwatch", "f4");

        [OnEventSystemInitialized]
        private static void RegisterEvents() {
            Unload();
            PublicEvents.OnEntityInstantiateEvent += PublicEventsOnEntityInstantiateEvent;
            PublicEvents.OnComponentAddedEvent += PublicEventsOnComponentAddedEvent;
            PublicEvents.OnComponentRemovedEvent += PublicEventsOnComponentRemovedEvent;
            PublicEvents.OnParentChangedEvent += PublicEventsOnParentChangedEvent;
            PublicEvents.OnEntityDestroyedEvent += PublicEventsOnEntityDestroyedEvent;
        }

        [OnEventSystemUnload]
        private static void Unload() {
            _combiners.Clear();
            _disabled = false;
            _disabledCompositeCombine = false;
            _enableComponentCompositeTypeCacher = null;
        }

        public static void Enable() {
            _disabled = false;
        }

        public static void Disable() {
            if (_disabled)
                return;

            _disabled = true;
            try {
                using var list = ListComponent<Combiner>.Rent();
                foreach (var kv in _combiners) {
                    var combiner = kv.Value;
                    list.Add(combiner);
                }

                foreach (var combiner in list) {
                    BreakAll(combiner);
                    CompositeBreakAll(combiner);
                    combiner.Dispose();
                }
            }
            finally {
                _combiners.Clear();
                ObjectPool.Clear<Combiner>();
            }
        }

        public static void EnableCompositeCombine() {
            _disabledCompositeCombine = false;
        }

        /*
         * single 组合的效率是非常快的, 而复合组合的效率, 虽然也很快, 但相比 single 会低很多, 尤其是当某个实体形成了大量的组合, 同时又需要频繁修改父级的时候, 如果对性能要求很高的话,
         * 可以禁用复合组合, 如果需要组合, 可以用纯手动的方式进行, 虽然麻烦, 但可以保证效率的最大化.
         */
        public static void DisableCompositeCombine() {
            if (_disabledCompositeCombine)
                return;

            _disabledCompositeCombine = true;
            using var list = ListComponent<Combiner>.Rent();
            foreach (var kv in _combiners) {
                var combiner = kv.Value;
                list.Add(combiner);
            }

            foreach (var combiner in list) {
                CompositeBreakAll(combiner);
            }
        }

        // 如果对复合组合的速度敏感, 可以使用这个功能, 把我们想要触发复合组合的组件添加进来, 只要我们添加过, 那么所有复合组合在运行时, 都会先判断是否存在, 否则就不执行
        public static void AddEnableCompositeCombine<T>() where T : Component {
            if (_combiners.Count != 0)
                throw new InvalidOperationException("Cant operate this when combined system is in using.");

            _enableComponentCompositeTypeCacher ??= ComponentTypeCacher.CreateEmpty();
            Component.CombineComponentType(_enableComponentCompositeTypeCacher, typeof(T));
        }

        public static void RemoveEnableCompositeCombine<T>() where T : Component {
            if (_combiners.Count != 0)
                throw new InvalidOperationException("Cant operate this when combined system is in using.");

            if (_enableComponentCompositeTypeCacher == null)
                return;

            _enableComponentCompositeTypeCacher.Remove(Component.GetComponentIndex<T>());
            if (_enableComponentCompositeTypeCacher.IsNullOrEmpty())
                _enableComponentCompositeTypeCacher = null;
        }

        private static void PublicEventsOnEntityInstantiateEvent(Entity entity) {
            if (_disabled)
                return;

            if (_combiners.ContainsKey(entity.InstanceId)) {
                throw new Exception("出问题了, 查查什么问题, 刚实例化出的实体, 怎么会已经存在了呢");
            }

            TryFormAll(entity);

            if (!_disabledCompositeCombine) {
                if (_enableComponentCompositeTypeCacher != null && !entity.HasComponentsAny(_enableComponentCompositeTypeCacher))
                    return;
                TryCompositeFormAll(entity);
            }
        }

        private static void PublicEventsOnComponentAddedEvent(Entity entity, Component component) {
            if (_disabled)
                return;

            TryForm(entity, component);

            if (!_disabledCompositeCombine) {
                if (_enableComponentCompositeTypeCacher != null && !entity.HasComponentsAny(_enableComponentCompositeTypeCacher))
                    return;
                TryCompositeForm(entity, component);
            }
        }

        private static void PublicEventsOnComponentRemovedEvent(Entity entity, Component component) {
            if (_disabled)
                return;

            TryBreak(entity, component);

            if (!_disabledCompositeCombine) {
                if (_enableComponentCompositeTypeCacher != null && !entity.HasComponentsAny(_enableComponentCompositeTypeCacher))
                    return;
                TryCompositeBreak(entity, component);
            }
        }

        private static void PublicEventsOnParentChangedEvent(Entity entity, Entity prev, Entity now, int layer) {
            if (entity.IsDisposing)
                return;

            if (_disabled)
                return;

            if (!_disabledCompositeCombine) {
                if (_enableComponentCompositeTypeCacher != null && !entity.HasComponentsAny(_enableComponentCompositeTypeCacher))
                    return;

                // 以prev为起点, 尝试把自己和自己的子级, 都向上断开
                if (prev != null) {
                    TryCompositeBreakForParent(entity, prev);
                }

                if (now != null) {
                    // 尝试和新的父级们形成组合
                    TryCompositeFormAll(entity);

                    // if (layer == 0) { // 只处理最上层
                    //     // 尝试和新的父级们形成组合
                    //     TryCompositeFormAll(entity);
                    //
                    //     // 对于那些要求的高的组合, 我们另外处理
                    //     var combinations = Combination.AllExtremeCompositeCombinations;
                    //     for (int i = 0, len = combinations.Count; i < len; i++) {
                    //         var combination = combinations[i];
                    //         TryForeachChildrenForm(entity, combination, int.MaxValue);
                    //     }
                    //
                    //     void TryForeachChildrenForm(Entity e, CompositeCombination combination, int maxlayer) {
                    //         if (maxlayer < 1)
                    //             return;
                    //
                    //         foreach (var child in e.ForeachChildrenExcludeGrandchild()) {
                    //             TryCompositeForm(child, combination);
                    //             maxlayer--;
                    //             TryForeachChildrenForm(child, combination, maxlayer);
                    //             maxlayer++;
                    //         }
                    //     }
                    // }
                }
            }
        }

        private static void PublicEventsOnEntityDestroyedEvent(Entity entity) {
            if (_disabled)
                return;

            BreakAll(entity);

            if (!_disabledCompositeCombine) {
                if (_enableComponentCompositeTypeCacher != null && !entity.HasComponentsAny(_enableComponentCompositeTypeCacher))
                    return;
                CompositeBreakAll(entity);
            }
        }

        public static Combiner GetCombiner(Entity entity) {
            if (_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return combiner;

            return null;
        }

        private static Combiner AddCombiner(Entity entity) {
            var combiner = ObjectPool.Rent<Combiner>();
            _combiners[entity.InstanceId] = combiner;
            combiner._entityInstanceId = entity.InstanceId;
            return combiner;
        }

        private static void TryRemoveCombiner(Combiner combiner) {
            if (combiner._matches.Count != 0)
                return;

            if (combiner._compositeMatches.Count != 0)
                return;

            var insid = combiner._entityInstanceId;
            combiner.Dispose();
            _combiners.Remove(insid);
            ObjectPool.Return(combiner);
        }

        #endregion

        private static readonly List<Component> _componentCache = new();
        private static readonly Stack<(Entity other, int position)> _compositeMatchCache = new();

        private int _entityInstanceId;
        private readonly Queue<int> _matches = new();
        private readonly Queue<CompositeMatchInfo> _compositeMatches = new();

        public int EntityInstanceId => this._entityInstanceId;

        #region Combination

        public static void TryFormAll(Entity entity) {
            // 遍历当前实体上, 所有有组合的组件, 并缓存他的组合, 用于后续匹配
            using var list = ListComponent<SingleCombination>.Rent();
            foreach (var componentIndex in entity.componentTypeCacher.Contains(Combination.TotulSingleCombinationsTypeCacher)) {
                if (Combination.TryGetSingleInfo(componentIndex, out var info)) {
                    for (int i = 0, len = info.relatedCombinations.Count; i < len; i++) {
                        var combination = info.relatedCombinations[i];
                        if (!list.Contains(combination))
                            list.Add(combination);
                    }
                }
            }

            TryForms(entity, list);
        }

        public static void TryForm(Entity entity, Component added) {
            if (!Combination.TryGetSingleInfo(added.ComponentIndex, out var combinInfo))
                return;

            TryForms(entity, combinInfo.relatedCombinations);
        }

        public static void TryForms(Entity entity, IList<SingleCombination> combinations, int maxMatchCount = int.MaxValue) {
            for (int i = 0, len = combinations.Count; i < len; i++) {
                var combination = combinations[i];
                // 如果成员数已经超出了当前可能出现的最大数, 就可以直接跳出, 剩下的也不需要尝试了
                if (combination.memberTypes.Length > maxMatchCount)
                    break;

                TryForm(entity, combination);
            }
        }

        public static void TryForm(Entity entity, SingleCombination combination) {
            if (_combiners.TryGetValue(entity.InstanceId, out var combiner)) {
                // 该组合已经存在
                if (combiner._matches.Contains(combination.id))
                    return;
            }

            // 判断能否形成组合
            if (entity.HasComponentsAll(combination.singleTypeCacher)) {
                if (combiner != null) {
                    var matchs = combiner._matches;
                    // 如果符合, 先判断该组合有没有覆盖者, 如果有, 则不能形成组合
                    if (Combination.InverseOverrides.TryGetValue(combination.id, out var ids)) {
                        foreach (var overrideCombinationId in ids) {
                            if (matchs.Contains(overrideCombinationId)) {
                                return;
                            }
                        }
                    }

                    // 再判断该组合有没有需要覆盖的, 如果有, 就断开其组合
                    if (Combination.Overrides.TryGetValue(combination.id, out ids)) {
                        foreach (var overrideCombinationId in ids) {
                            // 断开被覆盖的combin组合
                            var matchcount = matchs.Count;
                            while (matchcount-- > 0) {
                                var id = matchs.Dequeue();
                                if (id == overrideCombinationId) {
                                    var breakCombin = Combination.AllCombinations[overrideCombinationId];
                                    _componentCache.Clear();
                                    GetComponentsOfTypeCacher(entity, breakCombin.singleTypeCacher, _componentCache);
                                    breakCombin.Break_Internal(_componentCache);
                                    continue;
                                }

                                matchs.Enqueue(id);
                            }
                        }
                    }
                }

                // 正式形成新的组合
                combiner ??= AddCombiner(entity);
                combiner._matches.Enqueue(combination.id);
                _componentCache.Clear();
                GetComponentsOfTypeCacher(entity, combination.singleTypeCacher, _componentCache);
                combination.Form_Internal(_componentCache);
            }
        }

        public static void TryBreak(Entity entity, Component removed) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            var matchs = combiner._matches;
            if (matchs.Count == 0)
                return;

            try {
                // component可以为空, 如果为空, 则代表断开所有组合
                // 当有组件移除时, 说明有可能存在组合被断开了, 遍历已经所有已经组合的组合, 挨个匹配, 看看断掉的是哪个组合
                var componentIndex = removed.ComponentIndex;

                var combinations = Combination.AllCombinations;
                var count = matchs.Count;
                ListComponent<int> beoverlays = null; // 可能被覆盖的组合编号
                while (count-- > 0) {
                    var combinationId = matchs.Dequeue();
                    var combination = combinations[combinationId];
                    // 如果组合包含这个组件, 则删除该组件编号, 并触发事件
                    if (combination.singleTypeCacher.Contains(componentIndex)) {
                        _componentCache.Clear();
                        GetComponentsOfTypeCacher(entity, combination.singleTypeCacher, _componentCache);
                        _componentCache.Add(removed);
                        combination.Break_Internal(_componentCache);

                        // 记录所有的被覆盖者
                        if (Combination.Overrides.TryGetValue(combination.id, out var list)) {
                            beoverlays ??= ListComponent<int>.Rent();
                            for (int i = 0; i < list.Count; i++) {
                                beoverlays[i] = list[i];
                            }
                        }

                        continue;
                    }

                    matchs.Enqueue(combinationId);
                }

                if (beoverlays != null) {
                    // 对这些可能被覆盖的组合, 重新做一次匹配
                    for (int i = 0; i < beoverlays.Count; i++) {
                        var combination = Combination.AllCombinations[beoverlays[i]];
                        switch (combination) {
                            case SingleCombination singleCombination:
                                TryForm(entity, singleCombination);
                                break;

                            case CompositeCombination compositeCombination:
                                break;
                        }
                    }

                    beoverlays.Dispose();
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        public static void BreakAll(Entity entity) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            BreakAll(combiner);
        }

        public static void BreakAll(Combiner combiner) {
            var matchs = combiner._matches;
            if (matchs.Count == 0)
                return;

            try {
                var combinations = Combination.AllCombinations;
                var count = matchs.Count;
                while (count-- > 0) {
                    var combinationId = matchs.Dequeue();
                    var combination = combinations[combinationId];
                    _componentCache.Clear();
                    var entity = EventSystem.GetInstance<Entity>(combiner._entityInstanceId);
                    GetComponentsOfTypeCacher(entity, combination.singleTypeCacher, _componentCache);
                    combination.Break_Internal(_componentCache);
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        #endregion

        #region CompositeCombination

        public static void TryCompositeFormAll(Entity entity) {
            // 遍历当前实体上, 所有有组合的组件, 并缓存他的组合, 用于后续匹配
            using var list = ListComponent<CompositeCombination>.Rent();
            foreach (var componentIndex in entity.componentTypeCacher.Contains(Combination.TotulCompositeCombinationsLowestTypeCacher)) {
                if (Combination.TryGetCompositeInfo(componentIndex, out var info)) {
                    for (int i = 0, len = info.relatedCombinations.Count; i < len; i++) {
                        var (position, combination) = info.relatedCombinations[i];
                        if (position != 0)
                            continue; // 只缓存自己是最底层的组合

                        if (!list.Contains(combination))
                            list.Add(combination);
                    }
                }
            }

            TryCompositeForms(entity, list);
        }

        public static void TryCompositeForm(Entity entity, Component added) {
            if (!Combination.TryGetCompositeInfo(added.ComponentIndex, out var combinInfo))
                return;

            for (int i = 0, len = combinInfo.relatedCombinations.Count; i < len; i++) {
                var (position, combination) = combinInfo.relatedCombinations[i];
                switch (combination.CompositeCombinationMode) {
                    case CompositeCombinationMode.Normal: // 一般模式, 只向上做匹配
                        if (position == 0) {
                            TryCompositeForm(entity, combination);
                        }

                        break;
                    case CompositeCombinationMode.Extreme:
                        if (position == 0) {
                            TryCompositeForm(entity, combination);
                        }
                        else {
                            // 先获得可能的最低多少层
                            var downlayer = position;
                            var cachers = combination.compositeTypeCacher;
                            for (int j = position; j >= 0; j--) {
                                if (cachers[j] == null) {
                                    downlayer = int.MaxValue;
                                    break;
                                }
                            }

                            // 就在这个层的范围内, 遍历所有子级, 让他们挨个向上做匹配
                            ForeachChildren(entity, combination, downlayer);

                            void ForeachChildren(Entity e, CompositeCombination c, int maxlayer) {
                                if (maxlayer < 1)
                                    return;

                                foreach (var child in e.ForeachChildrenExcludeGrandchild()) {
                                    TryCompositeForm(child, c);
                                    maxlayer--;
                                    ForeachChildren(child, c, maxlayer);
                                    maxlayer++;
                                }
                            }
                        }

                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        public static void TryCompositeForms(Entity entity, IList<CompositeCombination> combinations) {
            for (int i = 0, len = combinations.Count; i < len; i++) {
                var combination = combinations[i];
                TryCompositeForm(entity, combination);
            }
        }

        public static void TryCompositeForm2(Entity entity, CompositeCombination combination) {
            var parent = entity.Parent;
            if (parent == null)
                return;

            _combiners.TryGetValue(entity.InstanceId, out var combiner);

            var typeGroup = combination.compositeTypeCacher[0]; // 自己是最低级, 向上匹配
            if (!entity.HasComponentsAll(typeGroup))
                return;

            // 向上级依次判断
            _compositeMatchCache.Clear();
            var succ = true;
            var contained = false;
            var jump = false;
            for (int i = 1, len = combination.compositeTypeCacher.Length; i < len; i++) {
                var parentTypeCacher = combination.compositeTypeCacher[i];
                if (parentTypeCacher == null) {
                    jump = true;
                    continue;
                }

                if (!jump) { // 不跳过, 就是逐级比对, 对不上, 就算失败
                    if (parent?.HasComponentsAll(parentTypeCacher) ?? false) {
                        if (!contained) { // 判存只需要和一个父级判就行了
                            contained = true;
                            if (combiner != null && ContainsCompositeMatch(combiner, parent.InstanceId, combination.id)) {
                                succ = false;
                                break;
                            }
                        }

                        _compositeMatchCache.Push((parent, i));
                        parent = parent.Parent;
                        continue;
                    }
                }
                else {
                    // 跳过, 则代表, 只要在父级中找到就行, 不管是在哪级找到的
                    var finded = false;
                    while (!finded && parent != null) {
                        if (parent.HasComponentsAll(parentTypeCacher)) {
                            if (!contained) {
                                contained = true;
                                if (combiner != null && ContainsCompositeMatch(combiner, parent.InstanceId, combination.id)) {
                                    succ = false;
                                    break;
                                }
                            }

                            finded = true;
                            jump = false;

                            _compositeMatchCache.Push((parent, i));
                        }

                        parent = parent.Parent;
                    }

                    if (finded)
                        continue;
                }

                // 都没找到, 失败
                succ = false;
                break;
            }


            if (succ) {
                var count = _compositeMatchCache.Count;
                // 判断覆盖相关

                // 正式形成组合
                var id = GenerateId();
                combiner ??= AddCombiner(entity);
                var combinerStorage = CompositeMatchCombinerStorage.Create(count + 1); // count + 1: 其他的 + 自己的一个
                combinerStorage.Combiners[0] = (combiner, 0); // 0位是自己的

                combiner._compositeMatches.Enqueue(new CompositeMatchInfo() {
                    id = id,
                    combinationId = combination.id,
                    selfPosition = 0,
                    combinerStorage = combinerStorage
                });
                _componentCache.Clear();
                GetComponentsOfTypeCacher(entity, typeGroup, _componentCache);

                var index = 1;
                while (count-- > 0) {
                    var (other, position) = _compositeMatchCache.Pop();
                    _combiners.TryGetValue(other.InstanceId, out var otherCombiner);
                    otherCombiner ??= AddCombiner(other);
                    combinerStorage.Combiners[index++] = (otherCombiner, position);
                    otherCombiner._compositeMatches.Enqueue(new CompositeMatchInfo() {
                        id = id,
                        combinationId = combination.id,
                        selfPosition = position,
                        combinerStorage = combinerStorage,
                    });
                    GetComponentsOfTypeCacher(other, combination.compositeTypeCacher[position], _componentCache);
                }

                _compositeMatchCache.Clear();
                combination.Form_Internal(_componentCache);
            }
        }

        public static void TryCompositeForm(Entity entity, CompositeCombination combination) {
            var parent = entity.Parent;
            if (parent == null)
                return;

            _combiners.TryGetValue(entity.InstanceId, out var combiner);

            var typeCacher = combination.compositeTypeCacher[0]; // 自己是最低级, 向上匹配
            if (!entity.HasComponentsAll(typeCacher))
                return;

            _compositeMatchCache.Clear();
            var succ = true;
            var contained = false;
            var parentLayer = 1;
            for (int i = 1, len = combination.compositeTypeCacher.Length; i < len; i++) {
                if (!succ)
                    break;

                var parentTypeCacher = combination.compositeTypeCacher[i];

                CONTINUE:
                if (parent == null) {
                    succ = false;
                    break;
                }

                var origParent = parent;
                var ret = combination.GetCustomRule(entity, ref parent, i, parentLayer);
                if (origParent != parent) { // 说明用户指定了新的parent
                    if (parent == null) {
                        succ = false;
                        break;
                    }
                }

                if (ret == CustomCompositeReturn.Succ) {
                    // 如果是自定义的规则, 我们还需要进行一次稳妥的判断
                    if (!parent.HasComponentsAll(parentTypeCacher))
                        throw new Exception(
                            $"Custom composite rule return succ, but get all coomponents in entity failure! 'Combination:{combination.GetType()}' 'GroupIndex:{i}'");
                }

                if (ret == CustomCompositeReturn.NoHanle) {
                    // 默认规则就是一层一层, 必须能严格的匹配上, 否则就失败
                    parent = origParent; // 还原 parent
                    ret = parent.HasComponentsAll(parentTypeCacher) ? CustomCompositeReturn.Succ : CustomCompositeReturn.Fail;
                }

                switch (ret) {
                    case CustomCompositeReturn.Succ:
                        if (!contained) { // 判存只需要和一个父级判就行了, 之所以放在这里判断, 是因为组件判存, 比如组合判存要快的多, 所以我们只当有可能成功时, 才进行一次判存
                            contained = true;
                            if (combiner != null && ContainsCompositeMatch(combiner, parent.InstanceId, combination.id)) {
                                succ = false;
                                break;
                            }
                        }

                        _compositeMatchCache.Push((parent, i));
                        NextParent();
                        break;
                    case CustomCompositeReturn.Fail:
                        succ = false;
                        break;
                    case CustomCompositeReturn.Next:
                        NextParent();
                        goto CONTINUE;
                    default:
                        throw new ArgumentOutOfRangeException();
                }

                continue;

                void NextParent() {
                    if (origParent != parent) {
                        if (!parent.IsParentOf(entity, out var layer))
                            throw new Exception(
                                $"CustomRule's specified parent must be parent of basic. Combination: '{combination.GetType()}' NextParent: '{parent.Name}'");
                        parentLayer = layer;
                    }

                    parent = parent.Parent;
                    parentLayer++;
                }
            }


            if (succ) {
                var count = _compositeMatchCache.Count;
                // 判断覆盖相关

                // 正式形成组合
                _componentCache.Clear();
                var id = GenerateId();
                combiner ??= AddCombiner(entity);
                var combinerStorage = CompositeMatchCombinerStorage.Create(count + 1); // count + 1: 其他的 + 自己的一个
                combinerStorage.Combiners[0] = (combiner, 0); // 0位是自己的

                combiner._compositeMatches.Enqueue(new CompositeMatchInfo() {
                    id = id,
                    combinationId = combination.id,
                    selfPosition = 0,
                    combinerStorage = combinerStorage
                });
                GetComponentsOfTypeCacher(entity, typeCacher, _componentCache);

                var index = 1;
                while (count-- > 0) {
                    var (other, position) = _compositeMatchCache.Pop();
                    _combiners.TryGetValue(other.InstanceId, out var otherCombiner);
                    otherCombiner ??= AddCombiner(other);
                    combinerStorage.Combiners[index++] = (otherCombiner, position);
                    otherCombiner._compositeMatches.Enqueue(new CompositeMatchInfo() {
                        id = id,
                        combinationId = combination.id,
                        selfPosition = position,
                        combinerStorage = combinerStorage,
                    });
                    GetComponentsOfTypeCacher(other, combination.compositeTypeCacher[position], _componentCache);
                }

                _compositeMatchCache.Clear();
                combination.Form_Internal(_componentCache);
            }
        }

        public static void TryCompositeForm(Entity entity, Entity other) {
            if (!other.IsParentOf(entity))
                throw new ArgumentException("other must be parent of basic entity");
        }

        public static void TryCompositeForm(Entity entity, IList<Entity> entities) {
            throw new NotImplementedException();
        }

        public static void TryCompositeBreak(Entity entity, Component removed) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return;

            var combinations = Combination.AllCombinations;
            try {
                var count = matchs.Count;
                while (count-- > 0) {
                    var matchInfo = matchs.Dequeue();
                    var combination = combinations[matchInfo.combinationId];
                    var typeCacher = combination.compositeTypeCacher[matchInfo.selfPosition];
                    if (typeCacher.Contains(removed.ComponentIndex)) {
                        BreakCompositeMatch(in matchInfo, _componentCache);
                        matchInfo.Free();
                        continue;
                    }

                    matchs.Enqueue(matchInfo);
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        public static void TryCompositeBreak(Entity entity, Entity other) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            if (!_combiners.ContainsKey(other.InstanceId))
                return;

            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return;

            try {
                var count = matchs.Count;
                while (count-- > 0) {
                    var matchInfo = matchs.Dequeue();
                    var storage = matchInfo.combinerStorage;
                    var b = false;
                    var cms = storage.Combiners;
                    for (int i = 0, len = storage.Count; i < len; i++) {
                        var tuple = cms[i];
                        if (tuple.combiner._entityInstanceId == other.InstanceId) {
                            b = true;
                            break;
                        }
                    }

                    if (b) {
                        BreakCompositeMatch(in matchInfo, _componentCache);
                        matchInfo.Free();
                        continue;
                    }

                    matchs.Enqueue(matchInfo);
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        public static void TryCompositeBreak(Entity entity, CompositeCombination combination) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return;

            try {
                var count = matchs.Count;
                while (count-- > 0) {
                    var matchInfo = matchs.Dequeue();
                    if (matchInfo.combinationId == combination.id) {
                        BreakCompositeMatch(in matchInfo, _componentCache);
                        matchInfo.Free();
                        continue;
                    }

                    matchs.Enqueue(matchInfo);
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        public static void TryCompositeBreakForParent(Entity entity, Entity parent) {
            var p = parent;
            while (p != null) {
                TryCompositeBreak(entity, p);
                p = p.Parent;
            }
        }

        public static void CompositeBreakAll(Entity entity) {
            if (!_combiners.TryGetValue(entity.InstanceId, out var combiner))
                return;

            CompositeBreakAll(combiner);
        }

        public static void CompositeBreakAll(Combiner combiner) {
            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return;

            try {
                var count = matchs.Count;
                while (count-- > 0) {
                    var matchInfo = matchs.Dequeue();
                    BreakCompositeMatch(in matchInfo, _componentCache);
                    matchInfo.Free();
                }
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        // 是否存在和某个实体组成的某个组合
        public static bool ContainsCompositeMatch(Combiner combiner, int instanceId, int combinationId) {
            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return false;

            foreach (var info in matchs) {
                if (info.combinationId != combinationId)
                    continue;

                var cms = info.combinerStorage.Combiners;
                for (int i = 0, len = info.combinerStorage.Count; i < len; i++) {
                    var tuple = cms[i];
                    if (tuple.combiner._entityInstanceId == instanceId)
                        return true;
                }
            }

            return false;
        }

        // 是否存在某个组合
        public static bool ContainsCompositeMatch(Combiner combiner, int combinationId) {
            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return false;

            foreach (var info in matchs) {
                if (info.combinationId == combinationId)
                    return true;
            }

            return false;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static int GenerateId() {
            return IdHelper.GenerateSimpleId();
        }

        private static void BreakCompositeMatch(in CompositeMatchInfo matchInfo, List<Component> cache) {
            try {
                var storage = matchInfo.combinerStorage;
                cache.Clear();
                var combination = Combination.AllCombinations[matchInfo.combinationId];
                var cms = storage.Combiners;
                for (int i = 0, len = storage.Count; i < len; i++) {
                    var tuple = cms[i];
                    var e = EventSystem.GetInstance<Entity>(tuple.combiner._entityInstanceId);
                    if (e == null) {
                        cache.Clear();
                        break;
                    }

                    var c = combination.compositeTypeCacher[tuple.position];
                    if (matchInfo.selfPosition != tuple.position)
                        RemoveCompositeMatch(tuple.combiner, matchInfo.id); // 也从其他的 combiner 里, 移除该 match
                    GetComponentsOfTypeCacher(e, c, cache);
                }

                if (cache.Count != 0)
                    combination.Break_Internal(cache);
            }
            catch (Exception e) {
                Log.Error(e);
            }
        }

        // 通过唯一id, 移除某个组合
        public static bool RemoveCompositeMatch(Combiner combiner, int id) {
            var matchs = combiner._compositeMatches;
            if (matchs.Count == 0)
                return false;

            try {
                var count = matchs.Count;
                while (count-- > 0) {
                    var match = matchs.Dequeue();
                    if (match.id == id)
                        return true;

                    matchs.Enqueue(match);
                }

                return false;
            }
            finally {
                TryRemoveCombiner(combiner);
            }
        }

        #endregion

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static void GetComponentsOfTypeCacher(Entity entity, ComponentTypeCacher cacher, List<Component> cache) {
            entity.GetComponentsOfTypeCacher(cacher, cache, true, true);
        }

        private void Dispose() {
            this._entityInstanceId = 0;
            this._matches.Clear();
            this._compositeMatches.Clear();
        }

        private struct CompositeMatchInfo {
            public int id; // 该 match 的唯一 id
            public int combinationId;
            public int selfPosition; // 自己在该组合中, 处于什么位置
            public CompositeMatchCombinerStorage combinerStorage; // 保存有形成该组合的所有combiner, 包括自己, 这是一个共享数据, 所有combiner里保存的是同一份

            public void Free() {
                this.combinerStorage.Dispose();
            }
        }

        // ReSharper disable once ClassNeverInstantiated.Local
        private class CompositeMatchCombinerStorage {
            public (Combiner combiner, int position)[] Combiners { get; private set; }
            public int Count { get; private set; }
            private bool _isDisposed;

            public static CompositeMatchCombinerStorage Create(int count) {
                if (count <= 0)
                    throw new ArgumentOutOfRangeException(nameof(count));

                var combiners = ObjectPool.Rent<CompositeMatchCombinerStorage>();
                combiners._isDisposed = false;
                combiners.Combiners = ArrayPool<(Combiner, int)>.Shared.Rent(count);
                combiners.Count = count;
                return combiners;
            }

            public void Dispose() {
                if (this._isDisposed)
                    return;

                this._isDisposed = true;

                this.Count = 0;
                ArrayPool<(Combiner, int)>.Shared.Return(this.Combiners, true);
                this.Combiners = null;
                ObjectPool.Return(this);
            }
        }
    }
}